/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  							 abstract_script_action.h

	$Header: /heroes4/abstract_script_action.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( ABSTRACT_SCRIPT_ACTION_H_INCLUDED )
#define ABSTRACT_SCRIPT_ACTION_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <cassert>
#include <iosfwd>
#include <memory>

#include "abstract_script_action_ptr.h"
#include "script_action_type.h"
#include "script_context_args.h"
#include "uncopyable.h"

class t_adventure_map;
class t_hero;
class t_town;
class t_army;
class t_adventure_object;
class t_basic_dialog;
class t_creature_array;

// --------------------------------------------------------------------------
// t_script_action class template - This class is intended to be secialized
// for each action type.
// --------------------------------------------------------------------------

template < t_script_action_type k_type >
class t_script_action {};

// --------------------------------------------------------------------------
// t_abstract_script_action class
// --------------------------------------------------------------------------

class t_abstract_script_action : public t_counted_object
{
public:
	// Types
	typedef	t_abstract_script_action_ptr				t_clone_ptr;
	typedef t_script_action_type						t_type;

	class t_factory;

	// Static member functions
	static	void		clear_removal();
	static  int			get_version();
	static	void		flag_for_removal();
	static	bool		pending_removal();

	static t_abstract_script_action_ptr reconstruct(
											std::streambuf &	stream,
											int version );
	
	static t_abstract_script_action_ptr	reconstruct_from_map(
											std::streambuf &	stream );
	static t_abstract_script_action_ptr	reconstruct_from_map(
											std::streambuf &	stream,
											int					format_version );


	// Destructor
	virtual ~t_abstract_script_action() {}

	// Member functions
	virtual void		add_icons(t_basic_dialog* dialog) const {}
	virtual t_clone_ptr	clone() const = 0;
	virtual t_type		get_type() const = 0;

	virtual void		execute(t_script_context_hero const& context) const {}
	virtual void		execute(t_script_context_town const& context) const {}
	virtual void		execute(t_script_context_object const& context) const {}
	virtual void		execute(t_script_context_army const& context) const {}
	virtual void		execute(t_script_context_global const& context) const {}
	virtual bool		read( std::streambuf &	stream, int version ) = 0;
	virtual bool		read_from_map(
							std::streambuf &	stream,
							int					format_version ) = 0;

	virtual bool		write( std::streambuf& stream ) const = 0;


private:
	static	t_abstract_script_action_ptr construct( std::streambuf& stream);	

	static	bool		m_removal_flag;

};

// --------------------------------------------------------------------------
// t_abstract_script_action::t_factory class
// --------------------------------------------------------------------------

class t_abstract_script_action::t_factory : private t_uncopyable
{
public:
	// Types
	typedef t_abstract_script_action_ptr	t_create_ptr;

	// Member functions
	virtual t_create_ptr	create() const = 0;

protected:
	// Constructor/Destructor
	explicit t_factory( t_type type );
	~t_factory() {}
};

// --------------------------------------------------------------------------
// t_script_action_factory class template
// --------------------------------------------------------------------------

template < t_script_action_type k_type >
class t_script_action_factory : public t_abstract_script_action::t_factory
{
public:
	// Types
	typedef t_script_action< k_type >	t_action;

	// Constructor
	t_script_action_factory();

	// Member functions
	virtual t_create_ptr	create() const;
};

// --------------------------------------------------------------------------
// t_script_action_factory member
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_action_type k_type >
inline t_script_action_factory< k_type >::t_script_action_factory()
	:	t_abstract_script_action::t_factory( k_type )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_action_type k_type >
typename t_script_action_factory< k_type >::t_create_ptr
t_script_action_factory< k_type >::create() const
{
	return t_create_ptr( new t_action );
}

// --------------------------------------------------------------------------
// t_script_action_base class template
// --------------------------------------------------------------------------

template < t_script_action_type k_type, typename t_base >
class t_script_action_base : public t_base
{
public:
	// Types
	typedef typename t_base::t_clone_ptr	t_clone_ptr;
	typedef t_script_action_type			t_type;

	// Member functions
	virtual t_clone_ptr	clone() const;
	virtual t_type		get_type() const;

private:
	// Static data members
	static t_script_action_factory< k_type > const k_factory;
};

// --------------------------------------------------------------------------
// t_script_action_base members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_action_type k_type, typename t_base >
t_script_action_factory< k_type > const t_script_action_base< k_type, t_base >::k_factory;

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_action_type k_type, typename t_base >
typename t_script_action_base< k_type, t_base >::t_clone_ptr
t_script_action_base< k_type, t_base >::clone() const
{
	typedef t_script_action< k_type > t_actual;
	assert( dynamic_cast< t_actual const * >( this ) != 0 );
	return t_clone_ptr( new t_actual( static_cast< t_actual const & >( *this ) ) );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < t_script_action_type k_type, typename t_base >
typename t_script_action_base< k_type, t_base >::t_type
t_script_action_base< k_type, t_base >::get_type() const
{
	// Force the instantiation of the factory
	&k_factory;
	return k_type;
}

// --------------------------------------------------------------------------
// SPECIALIZE_SCRIPT_ACTION() macro - used to create specializations of the
// t_script_action<> class template from t_abstract_script_action derived
// classes
// --------------------------------------------------------------------------

#define SPECIALIZE_SCRIPT_ACTION( k_type, t_base )	\
template <>											\
class t_script_action< k_type > : public t_script_action_base< k_type, t_base > {}

#endif // !defined( ABSTRACT_SCRIPT_ACTION_H_INCLUDED )
